package cn.skyquant.quant4j.jforex.strategy;

import cn.skyquant.quant4j.jforex.sdk.indicator.IndicatorUtils;
import cn.skyquant.quant4j.sdk.util.time.CalendarUtils;
import com.dukascopy.api.*;
import com.dukascopy.api.feed.IFeedDescriptor;
import com.dukascopy.api.feed.IFeedListener;
import com.dukascopy.api.feed.util.TimePeriodAggregationFeedDescriptor;

import java.io.PrintStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Library("quant4j-tools-1.0.jar;")
public class ATRTest implements IStrategy, IFeedListener {
    /*基本参数*/
    private IEngine engine;
    private IConsole console;
    private IHistory history;
    private IContext context;
    private IIndicators indicators;
    private IUserInterface userInterface;
    private PrintStream out;
    private PrintStream err;
    private IDataService dataService;
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Configurable("instrument")
    public Instrument sinstrument = Instrument.EURUSD;
    @Configurable("atr days")
    public int timePeriod = 22;
//    @Configurable("after")
//    public int after = 5;

    public IFeedDescriptor feedDescriptor;
    public IFeedDescriptor feedDescriptor1;
    public IFeedDescriptor feedDescriptor2;

    @Override
    public void onStart(IContext context) throws JFException {
        feedDescriptor = new TimePeriodAggregationFeedDescriptor(sinstrument, Period.DAILY, OfferSide.ASK);
        feedDescriptor1 = new TimePeriodAggregationFeedDescriptor(sinstrument, Period.ONE_MIN, OfferSide.ASK);
        feedDescriptor2 = new TimePeriodAggregationFeedDescriptor(sinstrument, Period.ONE_MIN, OfferSide.BID);
        this.engine = context.getEngine();
        this.console = context.getConsole();
        this.out = console.getOut();
        this.err = console.getErr();
        this.history = context.getHistory();
        this.context = context;
        this.indicators = context.getIndicators();
        this.userInterface = context.getUserInterface();
        dataService = context.getDataService();
        Set<Instrument> instrumentSet = new HashSet<>();
        instrumentSet.add(sinstrument);
//        instrumentSet.add(Instrument.USDJPY);
        context.setSubscribedInstruments(instrumentSet);

        context.subscribeToFeed(feedDescriptor, this);
        context.subscribeToFeed(feedDescriptor1, this);
        context.subscribeToFeed(feedDescriptor2, this);
        int i = 10;
        while (!context.getSubscribedInstruments().containsAll(instrumentSet) && i>=0) {
            try {
                console.getOut().println("Instruments not subscribed yet " + i);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                console.getOut().println(e.getMessage());
            }
            i--;
        }
//        context.setSubscribedInstruments(java.util.Collections.singleton(feedDescriptor.getInstrument()), true);
//        context.subscribeToFeed(feedDescriptor, this);
        IChart chart = context.getChart(sinstrument);//.openChart(feedDescriptor);
        out.println(chart.getFeedDescriptor());
        chart.add(indicators.getIndicator("TL_Boll"), new Object[]{20, 2.0, 2.0, IIndicators.MaType.EMA.ordinal()});
        chart.add(indicators.getIndicator("BBANDS"), new Object[]{20, 2.0, 2.0, IIndicators.MaType.EMA.ordinal()});
        chart.add(indicators.getIndicator("ATR"), new Object[]{timePeriod});
    }

    private boolean isOffline(long time) throws JFException {
        long t1 = time - Period.WEEKLY.getInterval();
        long t2 = time + Period.WEEKLY.getInterval();
        out.println("t1="+dateFormat.format(new Date(t1))+",t2="+dateFormat.format(new Date(t2)));
        Set<ITimeDomain> offlines = dataService.getOfflineTimeDomains(t1, t2);
        for (ITimeDomain offline : offlines) {
            out.println("offline.getStart()="+dateFormat.format(new Date(offline.getStart() ))+",offline.getEnd()="+dateFormat.format(new Date(offline.getEnd())));
            if (time > offline.getStart() && time < offline.getEnd()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void onTick(Instrument instrument, ITick tick) throws JFException {
//        console.getOut().println("onTick,"+instrument.getName()+","+tick);
    }

    @Override
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
//        if(period==Period.ONE_MIN){
//            console.getOut().println("onBar,"+instrument.getName()+",period="+period+",askbar="+askBar+",bidask="+bidBar);
//        }
//        if(period==Period.ONE_HOUR){
//            console.getOut().println(CalendarUtils.formatStandard(new Date(askBar.getTime()))+",offline0="+dataService.getOfflineTimeDomain()+",offline1="+dataService.getOfflineTimeDomain(-1));
//        }
        if(period==Period.DAILY && instrument==this.sinstrument){
            long to = askBar.getTime();
            long prevBarTime = history.getPreviousBarStart(Period.DAILY, history.getLastTick(instrument).getTime());

            String format = CalendarUtils.formatStandard(new Date(to));
            String format1 = CalendarUtils.formatSimple(new Date(prevBarTime));
            List<IBar> iBarList = history.getBars(instrument,Period.DAILY,OfferSide.ASK,Filter.WEEKENDS,timePeriod,prevBarTime,0);
            for(int i=0;i<iBarList.size();i++){
                //out.println(format+","+i+".bar="+iBarList.get(i));
            }
            double[] atrs = indicators.atr(instrument,Period.DAILY,OfferSide.ASK,timePeriod,Filter.WEEKENDS,1,prevBarTime,0);
            double atr = indicators.atr(instrument,Period.DAILY,OfferSide.ASK,timePeriod,0);
            double ratr = IndicatorUtils.atr(iBarList,timePeriod);
//            out.println("-----"+format+"---"+format1+",atr="+new BigDecimal(atr).setScale(instrument.getPipScale()+1, RoundingMode.HALF_UP)
//                    +",atr1="+new BigDecimal(atrs[atrs.length-1]).setScale(instrument.getPipScale()+1, RoundingMode.HALF_UP)
//                    +",ratr="+new BigDecimal(ratr).setScale(instrument.getPipScale()+1, RoundingMode.HALF_UP) );
            out.println(format1+" "+instrument.name()+"."+timePeriod+" days atr="+new BigDecimal(atrs[atrs.length-1]).setScale(instrument.getPipScale()+2, RoundingMode.HALF_UP));
        }
    }

    @Override
    public void onMessage(IMessage message) throws JFException {

    }

    @Override
    public void onAccount(IAccount account) throws JFException {

    }

    @Override
    public void onStop() throws JFException {

    }

    @Override
    public void onFeedData(IFeedDescriptor feedDescriptor, ITimedData feedData) {
//        try {
//            isOffline(feedData.getTime());
//        } catch (JFException e) {
//            e.printStackTrace();
//        }
//        if(feedDescriptor.equals(feedDescriptor1)){
//            out.println("ask feed="+feedData);
//        }
//        if(feedDescriptor.equals(feedDescriptor2)){
//            out.println("ask feed="+feedData);
//        }

        /*
        long time = feedData.getTime();
        Date date = new Date(time);
        String format = dateFormat.format(date);
        IBar iBar = (IBar) feedData;
        try {
            double atr = indicators.atr(feedDescriptor.getInstrument(), Period.DAILY, OfferSide.ASK, 30, 0);
            out.println(format + ":" + atr + ",isOffline:" + isOffline(time));
//            history.get(feedDescriptor.getInstrument(),Period.DAILY,OfferSide.ASK,0);
        } catch (JFException e) {
            e.printStackTrace();
        }*/
    }
}
